package com.sinotn.ks.node.camera.service.impl;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import com.sinotn.Page;
import com.sinotn.SinotnLogger;
import com.sinotn.component.KsFace;
import com.sinotn.gson.GsonFacade;
import com.sinotn.ks.definition.Computer;
import com.sinotn.ks.definition.ExamComputer;
import com.sinotn.ks.definition.ExamEngine;
import com.sinotn.ks.definition.ExamRoom;
import com.sinotn.ks.definition.Examinee;
import com.sinotn.ks.definition.TcpToken;
import com.sinotn.ks.netty.message.SimpleMessage;
import com.sinotn.ks.node.camera.bean.CameraPhotoBean;
import com.sinotn.ks.node.camera.dao.CameraPhotoDao;
import com.sinotn.ks.node.camera.dao.cond.CameraPhotoCond;
import com.sinotn.ks.node.camera.service.CameraService;
import com.sinotn.ks.node.camera.vo.CameraPhotoVO;
import com.sinotn.ks.node.runtime.FileStoreUtil;
import com.sinotn.ks.node.runtime.service.InvigilatorService;

public class DefaultCameraService implements CameraService {
	@Autowired
	private ExamEngine examEngine;
	@Autowired
	private CameraPhotoDao cameraDao;
	@Autowired
	private KsFace ksface;
	@Autowired
	private InvigilatorService invigilatorService;
	@Autowired
	private TcpToken tcpToken;

	@Override
	public CameraPhotoVO findCameraPhotoById(String id) {
		return cameraDao.selectCameraPhotoById(id);
	}

	@Override
	public void addCameraPhoto(CameraPhotoVO cameraPhotoVO) {
		cameraDao.insertCameraPhoto(cameraPhotoVO);
	}

	@Override
	public void modifyCameraPhoto(CameraPhotoVO cameraPhotoVO) {
		cameraDao.updateCameraPhoto(cameraPhotoVO);
	}

	@Override
	public void deleteCameraPhotoById(String id) {
		cameraDao.deleteCameraPhotoById(id);
	}

	@Override
	public void sendWarnCountToComputer() {
		CameraPhotoCond cond = new CameraPhotoCond();
		cond.setState((byte) 1);
		cond.setFixed((byte) 0);
		Map<String, Integer> map = cameraDao.selectWarningPhotos(cond);

		// 如果map不为空，则表示有警告信息的照片需要处理
		if (map != null && map.size() > 0) {
			boolean debug = SinotnLogger.DEBUG.isDebugEnabled();
			// 管理机分组 以管理机的注册key为key
			HashMap<String, Computer> managerComputers = new HashMap<String, Computer>();
			// 警告照片数分组 以管理机的注册key为key
			HashMap<String, Integer> totalCounts = new HashMap<String, Integer>();
			for (Entry<String, Integer> entry : map.entrySet()) {
				Integer count = entry.getValue(); // 该考场需要处理的照片数量

				if (count > 0) {

					String roomId = entry.getKey();
					ExamRoom room = examEngine.getExamRoom(roomId);
					if (room != null) {
						List<Computer> computers = room.allManageComputer();
						if (computers != null && computers.size() > 0) {
							for (Computer computer : computers) {
								if (!managerComputers.containsKey(computer.getRegKey())) {
									managerComputers.put(computer.getRegKey(), computer);
								}

								if (!totalCounts.containsKey(computer.getRegKey())) {
									totalCounts.put(computer.getRegKey(), 0);
								}
								int total = totalCounts.get(computer.getRegKey()) + count;
								totalCounts.put(computer.getRegKey(), total);
							}
						}
					}
				}
			}

			if (managerComputers.size() > 0) {
				Computer computer;
				int totalCount;
				HashMap<String, Object> body;
				for (Entry<String, Computer> entry : managerComputers.entrySet()) {
					computer = entry.getValue();
					totalCount = totalCounts.get(computer.getRegKey());
					if (debug) {
						SinotnLogger.DEBUG.debug("IP地址为" + computer.getIpAddr() + "的管理机有" + totalCount + "张照片需要处理。");
					}
					SimpleMessage sm = new SimpleMessage(104, this.tcpToken.nextToken());
					body = new HashMap<String, Object>();
					body.put("method", "camera#warning");
					body.put("text", totalCount);
					sm.setText(GsonFacade.toJson(body));
					computer.sendMessage(sm);
				}
			}
		}
	}

	@Override
	public void sendMsgByRoomId(String roomId) {
		HashSet<String> roomIds = new HashSet<String>();
		roomIds.add(roomId);
		CameraPhotoCond cond = new CameraPhotoCond();
		cond.setState((byte) 1);
		cond.setRoomIdSets(roomIds);
		cond.setFixed((byte) 0);
		Map<String, Integer> map = cameraDao.selectWarningPhotos(cond);
		if (map == null || map.size() == 0) {
			map.put(roomId, 0);
		}
		// 管理机分组 以管理机的注册key为key
		HashMap<String, Computer> managerComputers = new HashMap<String, Computer>();
		// 警告照片数分组 以管理机的注册key为key
		HashMap<String, Integer> totalCounts = new HashMap<String, Integer>();

		ExamRoom room = examEngine.getExamRoom(roomId);
		if (room != null) {
			List<Computer> computers = room.allManageComputer();
			if (computers != null && computers.size() > 0) {
				for (Computer computer : computers) {
					if (!managerComputers.containsKey(computer.getRegKey())) {
						managerComputers.put(computer.getRegKey(), computer);
					}

					if (!totalCounts.containsKey(computer.getRegKey())) {
						totalCounts.put(computer.getRegKey(), 0);
					}
					int total = totalCounts.get(computer.getRegKey()) + map.get(roomId);
					totalCounts.put(computer.getRegKey(), total);
				}
			}
		}
		Computer computer;
		int totalCount;
		HashMap<String, Object> body;
		for (Entry<String, Computer> entry : managerComputers.entrySet()) {
			computer = entry.getValue();
			totalCount = totalCounts.get(computer.getRegKey());
			SimpleMessage sm = new SimpleMessage(104, this.tcpToken.nextToken());
			body = new HashMap<String, Object>();
			body.put("method", "camera#warning");
			body.put("text", totalCount);
			sm.setText(GsonFacade.toJson(body));
			computer.sendMessage(sm);
		}
	}

	@Override
	public void photoCompareAutoHandle() {
		CameraPhotoCond cond = new CameraPhotoCond();
		cond.setState((byte) 0);
		cond.setFixed((byte) 0);
		//每次处理只处理前30条记录，避免异常情况累积大量待处理数据一次全加载内存溢出
		List<CameraPhotoVO> photoList = this.cameraDao.selectCameraPhotos(1, 30, cond);
		if(photoList==null || photoList.isEmpty()){
			return;
		}

		// 开启调试
		boolean debug = SinotnLogger.DEBUG.isDebugEnabled();
		// 如果不为空，就要做比对信息
		if (debug) {
			SinotnLogger.DEBUG.debug("需要人脸识别的照片有:" + photoList.size() + "张！");
		}
		int size=photoList.size();
		int faceCount, similar,faceCount2;
		String roomId,examineeId;
		File folder,signPhoto;
		File cameraFolder;
		File cameraPhoto=null;
		byte[] photoByte1,photoByte2;
		CameraPhotoVO vo;
		for (int i=0;i<size;i++) {
			vo=photoList.get(i);
			roomId = vo.getRoomId(); // 考场ID
			examineeId = vo.getExamineeId(); // 考生ID

			// 报名图片保存路径，如果没有报名图片文件夹，则退出循环，不作对比
			folder = FileStoreUtil.getPhotoFolder(roomId, false);
			if (folder == null || !folder.exists()) {
				vo.setState((byte) 4);
			}else{
				// 从文件夹找到对应考生ID的报名图片
				signPhoto = new File(folder, FileStoreUtil.getPhotoName(examineeId));
				if (signPhoto == null || !signPhoto.exists()) {
					vo.setState((byte) 4);
				} else {
					// 如果报名图片不为空，则与CameraPhoto进行比对
					cameraPhoto = null;
					cameraFolder = FileStoreUtil.getStoreFolder(roomId, examineeId, false);//new File(, "camera");// 摄像照片
					if (cameraFolder != null && cameraFolder.exists()) {
						cameraPhoto = new File(cameraFolder, "camera/" + vo.getPhotoPath());
					}
					if (cameraPhoto == null || !cameraPhoto.exists()) {
						vo.setState((byte) 4);
					}else{
						photoByte1 = new byte[5 * 1024];
						faceCount = ksface.faceconvert(cameraPhoto, photoByte1);
						if (debug) {
							SinotnLogger.DEBUG.debug(cameraPhoto.getName() + "人脸数的值:" + faceCount);
						}

						if(faceCount < 0){
							//环境或硬件不满足
							break;
						}
						if (faceCount > 0) {
							vo.setFaceCount(faceCount);
							photoByte2 = new byte[5 * 1024];
							faceCount2=ksface.faceconvert(signPhoto, photoByte2);
							if(faceCount2 < 0){
								//环境或硬件不满足
								break;
							}
							if(faceCount2>0){
								similar = ksface.facecompare(photoByte1, photoByte2);
								if (debug) {
									SinotnLogger.DEBUG.debug(cameraPhoto.getName() + "人脸相似度的值:" + faceCount);
								}
								vo.setSimilar(similar);
								if (similar < 450) {
									vo.setState((byte) 1);
									// 向考试机发送警告信息
									// this.sendMsgToKsComputer(vo.getExamineeId());
								} else {
									vo.setState((byte) 2);
								}
							}else{
								vo.setFaceCount(faceCount2);
								vo.setState((byte) 1);
							}
						} else {
							vo.setFaceCount(faceCount);
							vo.setState((byte) 1);
							// 向考试机发送警告信息
							// this.sendMsgToKsComputer(vo.getExamineeId());
						}
					}
				}
			}

			this.cameraDao.updateCameraPhoto(vo);// 更新数据
		}
	}

	/**
	 * 发送消息到考试机
	 *
	 * @param examineeId
	 * @auth <a href="mailto:liyunfeng@sinotn.com">李云峰</a>
	 * @date 2017年6月28日 下午4:27:37
	 */
	private void sendMsgToKsComputer(String examineeId) {
		Examinee examinee = examEngine.getExaminee(examineeId);
		if (examinee == null) {
			return;
		}
		ExamComputer computer = examinee.getExamComputer();
		if (computer == null) {
			return;
		}
		SimpleMessage sm = new SimpleMessage(1001, this.tcpToken.nextToken());
		Map<String, Object> body = new HashMap<String, Object>();
		body.put("method", "exam#resetWarning"); // TODO 这里还需要修改，客户端接口还未完成
		body.put("text", "");
		sm.setText(GsonFacade.toJson(body));
		computer.sendMessage(sm);
	}

	@Override
	public int findCameraPhotoCount() {
		return cameraDao.selectCameraPhotoCount();
	}

	@SuppressWarnings("unchecked")
	@Override
	public Page findCameraPhotoByPage(int pageIdx, int pageSize, CameraPhotoCond cond) {
		Page page = cameraDao.selectCameraPhotoByPage(pageIdx, pageSize, cond);
		List<CameraPhotoBean> list = new ArrayList<CameraPhotoBean>();
		CameraPhotoBean bean;
		for (CameraPhotoVO vo : (List<CameraPhotoVO>) page.getRows()) {
			bean = this.setCameraPhotoBean(vo);
			if (bean == null) {
				continue;
			}
			list.add(bean);
		}
		page.setRows(list);

		return page;
	}

	@Override
	public CameraPhotoBean findCameraPhotoInfo(String id) {
		CameraPhotoBean bean = null;

		CameraPhotoVO vo = cameraDao.selectCameraPhotoById(id);
		if (vo != null) {
			bean = new CameraPhotoBean();
			Examinee examinee = examEngine.getExaminee(vo.getExamineeId());
			if (examinee == null) {
				return null;
			}
			bean.setCameraPhoto(vo);
			bean.setExamineeName(vo.getExamineeName());
			bean.setExamCertId(examinee.getExamCertId());
			// 报名图片保存的http路径
			String signPhotoPath = examinee.getHttpPhoto();
			bean.setSignPhotoPath(signPhotoPath);

			String cameraPhotoPath = "";
			if (StringUtils.isNotBlank(signPhotoPath)) {
				int index = signPhotoPath.lastIndexOf(".jpg");
				cameraPhotoPath = signPhotoPath.substring(0, index) + "/" + vo.getPhotoPath();
			}
			bean.setCameraPhotoPath(cameraPhotoPath);
		}

		return bean;
	}

	@Override
	public void fixCameraPhoto(String id, String invigilatorId, String invigilatorName, String invigilatorPhone, String remark, byte fixed) {
		CameraPhotoVO vo = this.findCameraPhotoById(id);
		if (vo != null) {
			vo.setRemark(remark);
			vo.setInvigilatorName(invigilatorName);
			vo.setInvigilatorPhone(invigilatorPhone);
			vo.setFixed(fixed);
			vo.setState((byte) 3);

			this.modifyCameraPhoto(vo);
			this.sendMsgByRoomId(vo.getRoomId()); // 发送消息给管理机
			if (fixed == 1) {
				this.sendMsgToKsComputer(vo.getExamineeId());
			}
			if(fixed==2){
				Examinee examinee=this.examEngine.getExaminee(vo.getExamineeId());
				if(examinee!=null){
					this.invigilatorService.cheat(invigilatorId, vo.getRoomId(), examinee.getSeatNo(), "0017", "", "", remark);
				}
			}
		}
	}

	@Override
	public void delMultiPhotos(List<CameraPhotoVO> photoList) {
		cameraDao.deleteMultiPhotos(photoList);
	}

	@Override
	public List<CameraPhotoBean> findNormalPhotos(String examineeId, String roomId) {
		// 查找登录和交卷的两张照片
		List<CameraPhotoVO> photoList = cameraDao.selectNormalPhotoInExam(examineeId, roomId);
		if (photoList == null || photoList.size() == 0) {
			return new ArrayList<CameraPhotoBean>();
		}
		List<CameraPhotoBean> list = new ArrayList<CameraPhotoBean>();
		CameraPhotoBean bean;
		String signPhotoPath = "";
		Examinee examinee;
		File folder;
		File file;
		for (CameraPhotoVO vo : photoList) {
			if (vo != null) {
				bean = this.setCameraPhotoBean(vo);
				if (bean == null) {
					continue;
				}
				examinee = examEngine.getExaminee(vo.getExamineeId());
				// 报名图片保存的http路径
				signPhotoPath = examinee.getHttpPhoto();
				bean.setSignPhotoPath(signPhotoPath);
				folder=FileStoreUtil.getPhotoHttpFolder(examinee.getRoomId(), false);
				if(folder!=null){
					folder=new File(folder, examineeId);
					if(folder.exists()){
						file=new File(folder, vo.getId()+".mp3");
						if(file.exists()){
							bean.setMicPath("/examinee/"+examinee.getRoomId()+"/"+vo.getExamineeId()+"/"+file.getName());
						}
						file=new File(folder, vo.getPhotoPath());
						if(file.exists()){
							bean.setCameraPhotoPath("/examinee/"+examinee.getRoomId()+"/"+vo.getExamineeId()+"/"+vo.getPhotoPath());
						}
					}
				}
				list.add(bean);
			}
		}

		return list;
	}

	private CameraPhotoBean setCameraPhotoBean(CameraPhotoVO vo) {
		CameraPhotoBean bean = new CameraPhotoBean();
		bean.setCameraPhoto(vo);
		bean.setId(vo.getId());
		Examinee examinee = examEngine.getExaminee(vo.getExamineeId());
		if (examinee != null) {
			ExamRoom room = examEngine.getExamRoom(vo.getRoomId());
			bean.setExamineeName(examinee.getName());
			bean.setExamCertId(examinee.getExamCertId());
			bean.setRoomName(room.getName());
			bean.setRoomId(vo.getRoomId());
			bean.setExamineeId(vo.getExamineeId());
		} else {
			return null;
		}
		return bean;
	}

	@Override
	public List<CameraPhotoVO> findCameraPhotos(int pageIdx, int pageSize, CameraPhotoCond cond) {
		return this.cameraDao.selectCameraPhotos(pageIdx, pageSize, cond);
	}

	@Override
	public int modifyAnalyse(String id, byte state, int faceCount,int similar) {
		return this.cameraDao.updateAnalyse(id, state, faceCount, similar);
	}

	@Override
	public int getWarnPhotoCount(String roomId) {
		CameraPhotoCond cond = new CameraPhotoCond();
		cond.addRoomId(roomId);
		cond.setState((byte) 1);
		cond.setFixed((byte) 0);
		return this.cameraDao.selectCount(cond);
	}
}
